昨天介紹過了怎麼在 nest.js 裡面建立 chp555 MODE,今天我們來介紹如何在 NestJS 中建立 CRUD 操作,基本 CRUD 功能,包括創建報告、查詢報告、更新報告和移除報告。
首先,我們先來建立 Chp555 報告的 Controller 與 Service。Controller 負責接收 HTTP 請求並調用相應的服務方法,Service 則負責處理業務邏輯並與資料庫進行互動。
AuthGuard 是用來保護路由的守衛,在這裡我們使用 JWT 驗證,確保只有授權的用戶才能執行操作。Chp555ReportService 則是我們建立的 Service,用來處理報告的業務邏輯。import {
  Controller,
  Get,
  Post,
  Body,
  Patch,
  Param,
  Delete,
  Query,
  UseGuards,
} from '@nestjs/common';
import { Chp555ReportService } from './service/chp555Report.service';
import { AuthGuard } from '@nestjs/passport';
@Controller('chp555-report')
export class Chp555ReportController {
  constructor(private readonly chp555ReportService: Chp555ReportService) {}
  .....// 其他 CRUD 方法在此定義
  }
Injectable 來自 @nestjs/common,用來標記這個服務類別可以被注入。NotFoundException 用來在資料查詢不到時丟出 404 錯誤,提供更好的錯誤處理。InjectModel 來自 @nestjs/mongoose,用來注入 Mongoose 的資料模型。Model 則是 Mongoose 提供的,用來與 MongoDB 進行互動。Chp555Report 和 Party 分別是我們定義的報告與相關資料的模式,用來定義資料結構。import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Chp555Report } from '../schemas/CHP555Report/chp555Report.schema';
import { Party } from '../schemas/CHP555Report/Party/party.schema';
@Injectable()
export class Chp555ReportService {
  constructor(
    @InjectModel(Chp555Report.name)
    private readonly chp555ReportModel: Model<Chp555Report>,
    @InjectModel(Party.name)
    private readonly partyModel: Model<Party>,
  ) {}
  .... // 其他 CRUD 方法在此定義
  }
在建立報告的部分,create 方法負責接收來自用戶端的資料,並將其存入資料庫。這裡我們會同時建立三個 Party 資料作為報告的一部分,並將這些 Party 的 ID 保存到報告中。
我這邊採用一開始建立報告的時候就直接生成 三個 party的資料,後面採用更新填入。
router:  /chp555-report
method: post
  @Post()
  async create(@Body() createReportDto: any) {
    const data = await this.chp555ReportService.create(createReportDto);
    return {
      status: 'success',
      data: {
        reportId: data._id,
      },
    };
  }
  async create(createReportDto: any): Promise<Chp555Report> {
    const parties = [];
    for (let i = 0; i < 3; i++) {
      const newParty = new this.partyModel({
        order: i + 1,
      });
      const savedParty = await newParty.save();
      parties.push(savedParty._id);
    }
    const createdReport = new this.chp555ReportModel({
      ...createReportDto,
      partyies: parties,
    });
    return createdReport.save();
  }
對於查詢報告的部分,我們可以選擇查詢單個報告或所有報告。單個報告主要用來使用於查看單個報告或編輯。所有報告,可用來看報告記錄列表。但其實不應該傳這麼多資料回去。
router:   /chp555-report/:id
method: get
  @Get()
  async find(@Query('reportId') reportId?: string) {
    if (reportId) {
      // 如果有 reportId,查詢單個報告
      const data = await this.chp555ReportService.findOne(reportId);
      return {
        status: 'success',
        data,
      };
    } else {
      // 如果没有 reportId,查詢所有報告
      const data = await this.chp555ReportService.findAll();
      return {
        status: 'success',
        data,
      };
    }
  }
  async findAll(): Promise<Chp555Report[]> {
    return this.chp555ReportModel.find().exec();
  }
  async findOne(id: string): Promise<Chp555Report> {
    const report = await this.chp555ReportModel.findById(id).exec();
    if (!report) {
      throw new NotFoundException(`Report with ID ${id} not found`);
    }
    return report;
  }
當需要更新報告時,可以使用 PATCH 方法,更新指定的報告內容。
router:  /chp555-report
method: patch
  @Patch('report')
  async update(@Body() updateReportDto: any) {
    const data = await this.chp555ReportService.update(updateReportDto);
    return {
      status: 'success',
      data,
    };
  }
這邊先做簡單的錯誤處理,找不到報告的時候拋出錯誤。
  async update(updateReportDto: any): Promise<Chp555Report> {
    const id = updateReportDto.id;
    const updatedReport = await this.chp555ReportModel
      .findByIdAndUpdate(id, updateReportDto, { new: true })
      .exec();
    if (!updatedReport) {
      throw new NotFoundException(`Report with ID ${id} not found`);
    }
    return updatedReport;
  }
移除報告
router:  /chp555-report
method: delet
  @Delete(':id')
  async remove(@Param('id') id: string) {
    return this.chp555ReportService.remove(id);
  }
  async remove(id: string): Promise<void> {
    const result = await this.chp555ReportModel.findByIdAndDelete(id).exec();
    if (!result) {
      throw new NotFoundException(`Report with ID ${id} not found`);
    }
  }
回傳的資料我目前還沒詳細定義,就是把 Report的 model直接丟出來。
| 方法 | 路由 | 描述 | 請求參數 | 回應格式 | 
|---|---|---|---|---|
| POST | /chp555-report | 建立報告 | createReportDto (Body) | 
{ status: 'success', data: { reportId: string }} | 
| GET | /chp555-report | 查詢所有報告 | - | { status: 'success', data: Report[] } | 
| GET | /chp555-report | 查詢單個報告 | reportId (Query, 可選) | 
{ status: 'success', data: Report } | 
| PATCH | /chp555-report/report | 更新指定報告 | updateReportDto (Body) | 
{ status: 'success', data: Report } | 
| DELETE | /chp555-report/ | 刪除指定報告 | id (Path) | 
{ status: 'success' } | 
這邊是完整程式碼。
import {
  Controller,
  Get,
  Post,
  Body,
  Patch,
  Param,
  Delete,
  Query,
  UseGuards,
} from '@nestjs/common';
import { Chp555ReportService } from './service/chp555Report.service';
import { AuthGuard } from '@nestjs/passport';
@Controller('chp555-report')
export class Chp555ReportController {
  constructor(private readonly chp555ReportService: Chp555ReportService) {}
  @UseGuards(AuthGuard('jwt'))
  @Post()
  async create(@Body() createReportDto: any) {
    const data = await this.chp555ReportService.create(createReportDto);
    return {
      status: 'success',
      data: {
        reportId: data._id,
      },
    };
  }
  @UseGuards(AuthGuard('jwt'))
  @Get()
  async find(@Query('reportId') reportId?: string) {
    if (reportId) {
      const data = await this.chp555ReportService.findOne(reportId);
      return {
        status: 'success',
        data,
      };
    } else {
      const data = await this.chp555ReportService.findAll();
      return {
        status: 'success',
        data,
      };
    }
  }
  @UseGuards(AuthGuard('jwt'))
  @Patch('report')
  async update(@Body() updateReportDto: any) {
    const data = await this.chp555ReportService.update(updateReportDto);
    return {
      status: 'success',
      data,
    };
  }
  @UseGuards(AuthGuard('jwt'))
  @Delete(':id')
  async remove(@Param('id') id: string) {
    return this.chp555ReportService.remove(id);
  }
}
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Chp555Report } from '../schemas/CHP555Report/chp555Report.schema';
import { Party } from '../schemas/CHP555Report/Party/party.schema';
import {
  SpecialConditionEnum,
  SpecialConditionName,
} from '../../const/eumns/chp555Report';
@Injectable()
export class Chp555ReportService {
  constructor(
    @InjectModel(Chp555Report.name)
    private readonly chp555ReportModel: Model<Chp555Report>,
    @InjectModel(Party.name)
    private readonly partyModel: Model<Party>,
  ) {}
  async create(createReportDto: any): Promise<Chp555Report> {
    const parties = [];
    for (let i = 0; i < 3; i++) {
      const newParty = new this.partyModel({
        order: i + 1,
      });
      const savedParty = await newParty.save();
      parties.push(savedParty._id);
    }
    const createdReport = new this.chp555ReportModel({
      ...createReportDto,
      partyies: parties,
    });
    return createdReport.save();
  }
  async findAll(): Promise<Chp555Report[]> {
    return this.chp555ReportModel.find().exec();
  }
  async findOne(id: string): Promise<Chp555Report> {
    const report = await this.chp555ReportModel.findById(id).exec();
    if (!report) {
      throw new NotFoundException(`Report with ID ${id} not found`);
    }
    return report;
  }
  async update(updateReportDto: any): Promise<Chp555Report> {
    const id = updateReportDto.id;
    const updatedReport = await this.chp555ReportModel
      .findByIdAndUpdate(id, updateReportDto, { new: true })
      .exec();
    if (!updatedReport) {
      throw new NotFoundException(`Report with ID ${id} not found`);
    }
    return updatedReport;
  }
  async remove(id: string): Promise<void> {
    const result = await this.chp555ReportModel.findByIdAndDelete(id).exec();
    if (!result) {
      throw new NotFoundException(`Report with ID ${id} not found`);
    }
  }
}
實作完成建議要使用 postman做測試,這樣才會知道是否符合需求。明天來實作串接到APP
#it鐵人